﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

using Microsoft.VisualBasic;

using Google.Apis;
using Google.Apis.Util;
using Google.Apis.Samples.Helper;
using Google.Apis.Authentication;
using Google.Apis.Authentication.OAuth2;
using Google.Apis.Authentication.OAuth2.DotNetOpenAuth;
using DotNetOpenAuth.OAuth2;
using Google.Apis.Oauth2.v2;
using Google.Apis.Tasks.v1;
using Google.Apis.Tasks.v1.Data;
using GoogleTasksMigrator.Custom.Extensions;


namespace GoogleTasksMigrator
{
    class NotConnectedException : Exception
    {
        public NotConnectedException(string msg)
            : base(String.Format("{0} : not connected to a Google account. Use Connect() first.", msg))
        {
        }
    }

    class GTasksManager
    {
        private TasksService _tasks_service = null;
        private Oauth2Service _oauth2_service = null;
        private string _authentication_token = null;

        public GTasksManager(string auth_token="")
        {
            _authentication_token = auth_token;
        }

        public String Email
        {
            get
            {
                if (_oauth2_service == null)
                    throw new NotConnectedException("Cannot retrieve Email");
                return _oauth2_service.Userinfo.V2.Me.Get().Fetch().Email;
            }
        }
        public TaskLists TaskLists
        {
            get
            {
                if (_tasks_service == null)
                    throw new NotConnectedException("Cannot list Tasks");
                return _tasks_service.Tasklists.List().Fetch();
            }
        }

        public TaskList GetTaskList(string list_id)
        {
            if (_tasks_service == null)
                throw new NotConnectedException("Cannot get TaskList");
            return _tasks_service.Tasklists.Get(list_id).Fetch();
        }
        public Task GetTask(string list_id, string task_id)
        {
            if (_tasks_service == null)
                throw new NotConnectedException("Cannot get Task");
            return _tasks_service.Tasks.Get(list_id, task_id).Fetch();
        }

        public Tasks GetTasks(string list_id)
        {
            if (_tasks_service == null)
                throw new NotConnectedException("Cannot list Tasks");
            return _tasks_service.Tasks.List(list_id).Fetch();
        }

        public TaskList InsertList(TaskList list)
        {
            if (_tasks_service == null)
                throw new NotConnectedException("Cannot insert TaskList");
            return _tasks_service.Tasklists.Insert(list).Fetch();
        }
        public Task InsertTask(Task task, string list_id)
        {
            if (_tasks_service == null)
                throw new NotConnectedException("Cannot insert Task");
            return _tasks_service.Tasks.Insert(task, list_id).Fetch();
        }

        public void DeleteList(string list_id)
        {
            if (_tasks_service == null)
                throw new NotConnectedException("Cannot delete TaskList");
            _tasks_service.Tasklists.Delete(list_id).Fetch();
        }
        public void DeleteTask(string task_id, string list_id)
        {
            if (_tasks_service == null)
                throw new NotConnectedException("Cannot delete Task");
            _tasks_service.Tasks.Delete(task_id, list_id).Fetch();
        }


        private static IAuthorizationState GetAuthorization(NativeApplicationClient arg)
        {
            // Get the auth URL:
            IAuthorizationState state = new AuthorizationState(new[] { 
                TasksService.Scopes.Tasks.GetStringValue(), 
                Oauth2Service.Scopes.UserinfoEmail.GetStringValue(),
                Oauth2Service.Scopes.UserinfoProfile.GetStringValue() });

            state.Callback = new Uri(NativeApplicationClient.OutOfBandCallbackUrl);
            Uri authUri = arg.RequestUserAuthorization(state);

            // Retrieve the access token by using the authorization code:
            string authCode = _authentication_token;
            GetAuthToken(arg.ClientIdentifier, authUri);
            return arg.ProcessUserAuthorization(authCode, state);
        }

        private static string GetAuthToken(string client_id, Uri auth_uri)
        {
            if (client_id == Properties.Settings.Default.SrcClientID)
            {
                if (Properties.Settings.Default.SrcAuthToken == "") // todo : check actual validity
                {
                    // Request authorization from the user (by opening a browser window):
                    System.Diagnostics.Process.Start(auth_uri.ToString());
                    Properties.Settings.Default.SrcAuthToken = Interaction.InputBox("Authorization Code : ", "Accès au compte source");
                    Properties.Settings.Default.Save();
                }
                return Properties.Settings.Default.SrcAuthToken;
            }
            else if ( client_id == Properties.Settings.Default.DestClientID )
            {
                if (Properties.Settings.Default.DestAuthToken == "") // todo : check actual validity
                {
                    // Request authorization from the user (by opening a browser window):
                    System.Diagnostics.Process.Start(auth_uri.ToString());
                    Properties.Settings.Default.DestAuthToken = Interaction.InputBox("Authorization Code : ", "Accès au compte cible");
                    Properties.Settings.Default.Save();
                }
                return Properties.Settings.Default.DestAuthToken;
            }
            return "";
        }

        public void Connect()
        {
            try
            {
                // Register the authenticator.
                var auth_provider = new NativeApplicationClient(GoogleAuthenticationServer.Description);
                auth_provider.ClientIdentifier = Properties.Resources.SrcClientIdentifier;
                auth_provider.ClientSecret = Properties.Resources.SrcClientSecret;
                var src_auth = new OAuth2Authenticator<NativeApplicationClient>(auth_provider, GetAuthorization);
                _tasks_service = new TasksService(src_auth);
                _oauth2_service = new Oauth2Service(src_auth);
            }
            catch (Exception ex)
            {
                throw new Exception(String.Format("!! ERROR during connection process :{0} !!", ex.Message));
            }
        }

    }
}
